package com.ts.api.http.org.biz;

import com.alibaba.fastjson.JSONObject;
import com.gitee.apanlh.util.base.ChooseEq;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.base.MapUtils;
import com.gitee.apanlh.util.dataformat.JsonUtils;
import com.gitee.apanlh.web.http.HttpContentType;
import com.ts.api.http.org.entity.apply.ApiOrgApplyNanNingRongShi;
import com.ts.api.module.api.convert.core.annotation.ApiPlan;
import com.ts.api.module.api.convert.core.annotation.ApiPlanConvertType;
import com.ts.api.module.api.convert.core.entity.ApiApplyParameter;
import com.ts.api.module.api.convert.core.entity.ApiDataExchangeParameter;
import com.ts.api.module.api.convert.core.utils.ApiFieldConverter;
import com.ts.api.module.api.convert.org.handler.ApiOrgPhoneMd5ConvertHandler;
import com.ts.api.module.api.convert.org.model.RespOrgPhoneMd5Apply;
import com.ts.api.module.api.convert.org.model.RespOrgPhoneMd5DataExchange;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * 南宁融时 API 小速花
 * https://www.yuque.com/u44925343/gluy5q/go7czspnpyiz0pzx
 * @author 李源聪
 * PS:文档中有需要说重排序，实际情况在撞库和进件中都不需要重排序，实体类直接转json加密发送即可
 */
@ApiPlan(productId = "21", type = ApiPlanConvertType.ORG_PHONE_MD5)
public class ApiOrgPhoneMd5NanNingRongShi implements ApiOrgPhoneMd5ConvertHandler {

    private static final String KEY= "AxfqxC589g135Qxi";
    private static final String IV= "Ky2YDTI0AbMVljBg";

    private static final Map<String, Cipher> CIPHERMAP_MAP = new HashMap<String, Cipher>();
    private static final String DEFAULT_CHARSET = "utf-8";
    private static final String ALGORITHM_NAME = "AES";
    private static final String ALGORITHM_STR = ALGORITHM_NAME + "/CBC/PKCS5Padding";

    @Override
    public Object dataExchange(ApiDataExchangeParameter apiDataExchangeParameter) throws Exception {
        Map<String,Object> object = new HashMap<>();
        object.put("phone_md5", apiDataExchangeParameter.getPhoneMd5());
        String encrypt = encrypt(JsonUtils.toJson(object), KEY, IV);
        apiDataExchangeParameter.setHttpContentType(HttpContentType.APPLICATION_JSON);

        Map<String, Object> map = MapUtils.newHashMap(newMap -> {
            newMap.put("channelSign", KEY);
            newMap.put("data", encrypt);
        });
        return JsonUtils.toJson(map);
    }

    @Override
    public RespOrgPhoneMd5DataExchange respDataExchange(String respJson) throws Exception {
        JSONObject jsonObject = JsonUtils.get(respJson);
        if (jsonObject == null) {
            return RespOrgPhoneMd5DataExchange.ofFail();
        }
        if (!Eq.object(jsonObject.getInteger("code"), 200)) {
            return RespOrgPhoneMd5DataExchange.ofFail();
        }
        return RespOrgPhoneMd5DataExchange.ofSuc();
    }

    @Override
    public Object apply(ApiApplyParameter apiApplyParameter) throws Exception {
        ApiOrgApplyNanNingRongShi customerInfo = new ApiOrgApplyNanNingRongShi();
        // 姓名
        customerInfo.getCustomerInfo().setName(apiApplyParameter.getUserName());
        // 性别(1.男，2.女)
        Integer sexChoose = ChooseEq.create()
                .when(apiApplyParameter.getSex(), "0", 1)
                .when(apiApplyParameter.getSex(), "1", 2)
                .end(1);
        customerInfo.getCustomerInfo().setGender(sexChoose);
        // 城市名称
        customerInfo.getCustomerInfo().setCityName(apiApplyParameter.getCity());
        // 学历: 1-高中及以下, 2-大专/本科, 3-硕士及以上
        Integer eduChoose = ChooseEq.create()
                .when(apiApplyParameter.getEducationAttainment(), "1", 1)
                .when(apiApplyParameter.getEducationAttainment(), "2", 1)
                .when(apiApplyParameter.getEducationAttainment(), "3", 1)
                .when(apiApplyParameter.getEducationAttainment(), "4", 2)
                .when(apiApplyParameter.getEducationAttainment(), "5", 2)
                .when(apiApplyParameter.getEducationAttainment(), "6", 3)
                .end();
        customerInfo.getCustomerInfo().setEducation(eduChoose);
        // 职业类型: 1-自雇人士, 2-工薪族, 3-三无, 4-其他
        Integer careerChoose = ChooseEq.create()
                .when(apiApplyParameter.getCareer(), "1", 2)
                .when(apiApplyParameter.getCareer(), "2", 1)
                .when(apiApplyParameter.getCareer(), "3", 2)
                .when(apiApplyParameter.getCareer(), "4", 2)
                .when(apiApplyParameter.getCareer(), "5", 3)
                .end();
        customerInfo.getCustomerInfo().setJobType(careerChoose);
        // 身份证号码
        customerInfo.getCustomerInfo().setIdcard(apiApplyParameter.getIdcard());
        // 年龄
        ApiFieldConverter apiFieldConverter = ApiFieldConverter.create(apiApplyParameter);
        customerInfo.getCustomerInfo().setAge(apiFieldConverter.getAgeInt());
        // 手机号码
        customerInfo.getCustomerInfo().setPhoneNumber(apiApplyParameter.getPhone());
        customerInfo.getCustomerInfo().setPhoneMd5(apiApplyParameter.getPhoneMd5());
        // 贷款金额（1. 0-3万，2. 3-5万，3. 10-20万，4. 20万以上，5. 1万-5万，6. 1万以内，7. 其他）
        Integer loanAmountChoose = ChooseEq.create()
                .when(apiApplyParameter.getLoanAmount(), "1", 1)
                .when(apiApplyParameter.getLoanAmount(), "2", 2)
                .when(apiApplyParameter.getLoanAmount(), "3", 3)
                .when(apiApplyParameter.getLoanAmount(), "4", 4)
                .end();
        customerInfo.getCustomerRequirements().setLoanAmount(loanAmountChoose);
        // 贷款用途（1. 消费，2. 装修，3. 购车买房，4. 经营周转，5. 其他）
        Integer loanPurposeChoose = ChooseEq.create()
                .when(apiApplyParameter.getLoanPurpose(), "1", 1)
                .when(apiApplyParameter.getLoanPurpose(), "2", 1)
                .when(apiApplyParameter.getLoanPurpose(), "3", 1)
                .when(apiApplyParameter.getLoanPurpose(), "4", 2)
                .when(apiApplyParameter.getLoanPurpose(), "5", 1)
                .when(apiApplyParameter.getLoanPurpose(), "6", 1)
                .end();
        customerInfo.getCustomerRequirements().setLoanPurpose(loanPurposeChoose);
        // 银行代发
        String salaryPayMethodChoose = ChooseEq.create()
                .when(apiApplyParameter.getSalaryPayMethod(), "1", "银行代发打卡")
                .when(apiApplyParameter.getSalaryPayMethod(), "2", "现金收入")
                .when(apiApplyParameter.getSalaryPayMethod(), "3", "个人转账")
                .end();
        customerInfo.getCustomerDetails().setBankPayroll(salaryPayMethodChoose);
        // 社保状态（0. 无，1. 有）
        String socialSecurityChoose = ChooseEq.create()
                .when(apiApplyParameter.getSocialSecurity(), "1", "0")
                .when(apiApplyParameter.getSocialSecurity(), "2", "1")
                .when(apiApplyParameter.getSocialSecurity(), "3", "1")
                .when(apiApplyParameter.getSocialSecurity(), "4", "1")
                .end();
        customerInfo.getCustomerDetails().setSocialSecurityStatus(socialSecurityChoose);
        // 公积金 （0. 无，1. 有）
        Integer providentFundChoose = ChooseEq.create()
                .when(apiApplyParameter.getProvidentFund(), "1", 0)
                .when(apiApplyParameter.getProvidentFund(), "2", 1)
                .when(apiApplyParameter.getProvidentFund(), "3", 1)
                .when(apiApplyParameter.getProvidentFund(), "4", 1)
                .end();
        customerInfo.getCustomerDetails().setProvidentFundStatus(providentFundChoose);
        // 打卡工资: 0-无打卡工资, 1-1万及以下, 2-1.1万~2万, 3-2.1万~5万, 4-5.1万及以上
        Integer monthlySalaryFundChoose = ChooseEq.create()
                .when(apiApplyParameter.getMonthlySalary(), "1", 1)
                .when(apiApplyParameter.getMonthlySalary(), "2", 1)
                .when(apiApplyParameter.getMonthlySalary(), "3", 2)
                .when(apiApplyParameter.getMonthlySalary(), "4", 2)
                .when(apiApplyParameter.getMonthlySalary(), "5", 3)
                .end();
        customerInfo.getCustomerAssets().setSalaryRange(monthlySalaryFundChoose);
        // 房产（1有/0无）
        Integer realEstateInfoChoose = ChooseEq.create()
                .when(apiApplyParameter.getRealEstateInfo(), "1", 0)
                .when(apiApplyParameter.getRealEstateInfo(), "2", 1)
                .when(apiApplyParameter.getRealEstateInfo(), "3", 1)
                .when(apiApplyParameter.getRealEstateInfo(), "4", 1)
                .when(apiApplyParameter.getRealEstateInfo(), "5", 1)
                .when(apiApplyParameter.getRealEstateInfo(), "6", 1)
                .end();
        customerInfo.getCustomerAssets().setHouseProperty(realEstateInfoChoose);
        // 车产（1有/0无）
        Integer carInfoChoose = ChooseEq.create()
                .when(apiApplyParameter.getCarInfo(), "1", 0)
                .when(apiApplyParameter.getCarInfo(), "2", 1)
                .when(apiApplyParameter.getCarInfo(), "3", 1)
                .when(apiApplyParameter.getCarInfo(), "4", 1)
                .end();
        customerInfo.getCustomerAssets().setCarProperty(carInfoChoose);
        // 保单（1有/0无）
        Integer insurancePolicyChoose = ChooseEq.create()
                .when(apiApplyParameter.getInsurancePolicy(), "1", 0)
                .when(apiApplyParameter.getInsurancePolicy(), "2", 1)
                .when(apiApplyParameter.getInsurancePolicy(), "3", 1)
                .when(apiApplyParameter.getInsurancePolicy(), "4", 1)
                .end();
        customerInfo.getCustomerAssets().setBdStatus(insurancePolicyChoose);
        // 花呗白条额度
        String btLimitChoose = ChooseEq.create()
                .when(apiApplyParameter.getBtLimit(), "1", "0")
                .when(apiApplyParameter.getBtLimit(), "2", "3000")
                .when(apiApplyParameter.getBtLimit(), "3", "10000")
                .when(apiApplyParameter.getBtLimit(), "4", "20000")
                .when(apiApplyParameter.getBtLimit(), "5", "30000")
                .end();
        customerInfo.getCustomerAssets().setHuabeiBaitiao(btLimitChoose);
        // 花呗白条额度
        String hbLimitChoose = ChooseEq.create()
                .when(apiApplyParameter.getHbLimit(), "1", "0")
                .when(apiApplyParameter.getHbLimit(), "2", "3000")
                .when(apiApplyParameter.getHbLimit(), "3", "10000")
                .when(apiApplyParameter.getHbLimit(), "4", "20000")
                .when(apiApplyParameter.getHbLimit(), "5", "30000")
                .end();
        customerInfo.getCustomerAssets().setHuabeiBaitiao(hbLimitChoose);
        // 芝麻信用分
        Integer sesameCreditChoose = ChooseEq.create()
                .when(apiApplyParameter.getSesameCredit(), "1", 600)
                .when(apiApplyParameter.getSesameCredit(), "2", 649)
                .when(apiApplyParameter.getSesameCredit(), "3", 699)
                .when(apiApplyParameter.getSesameCredit(), "4", 700)
                .end();
        customerInfo.getCustomerAssets().setSesameCreditScore(sesameCreditChoose);
        // 有无逾期（0.无，1.有）
        Integer overdueChoose = ChooseEq.create()
                .when(apiApplyParameter.getOverdue(), "1", 0)
                .when(apiApplyParameter.getOverdue(), "2", 1)
                .when(apiApplyParameter.getOverdue(), "3", 1)
                .end();
        customerInfo.getCreditInformation().setCreditOverdue(overdueChoose);
        // 信用卡总金额
        String creditLimit = ChooseEq.create()
                .when(apiApplyParameter.getCreditLimit(), "1", "0")
                .when(apiApplyParameter.getCreditLimit(), "2", "3000")
                .when(apiApplyParameter.getCreditLimit(), "3", "10000")
                .when(apiApplyParameter.getCreditLimit(), "4", "30000")
                .when(apiApplyParameter.getCreditLimit(), "5", "35000")
                .when(apiApplyParameter.getCreditLimit(), "6", "3000")
                .end();
        customerInfo.getCreditInformation().setCreditCardTotalAmount(creditLimit);

        apiApplyParameter.setHttpContentType(HttpContentType.APPLICATION_JSON);

        String encryptData = encrypt(JsonUtils.toJson(customerInfo),KEY, IV);
        Map<String, Object> map = MapUtils.newHashMap(newMap -> {
            newMap.put("channelSign", KEY);
            newMap.put("data",encryptData);
        });
        return JsonUtils.toJson(map);
    }

    @Override
    public RespOrgPhoneMd5Apply respApply(String respJson) throws Exception {
        JSONObject jsonObject = JsonUtils.get(respJson);
        if (jsonObject == null) {
            return RespOrgPhoneMd5Apply.ofFail();
        }
        if (!Eq.object(jsonObject.getInteger("code"), 200)) {
            return RespOrgPhoneMd5Apply.ofFail();
        }
        return RespOrgPhoneMd5Apply.ofSuc();
    }

    public static String encrypt(String a, String key,String iv) throws Exception {
        return encrypt(a, key, DEFAULT_CHARSET,iv);
    }

    public static String decrypt(String a, String key,String iv) throws Exception {
        return decrypt(a, key, DEFAULT_CHARSET,iv);
    }

    public static String encrypt(String a, String key, String charset,String iv) throws Exception {
        Cipher cipher = getCipher(Cipher.ENCRYPT_MODE, key, charset,iv);
        byte[] resultByte = cipher.doFinal(a.getBytes(charset));
        return base64BytesToString(resultByte, charset);
    }

    public static String decrypt(String a, String key, String charset,String iv) throws Exception {
        Cipher cipher = getCipher(Cipher.DECRYPT_MODE, key, charset,iv);
        byte[] inputByte = base64stringToBytes(a, charset);
        byte[] resultByte = cipher.doFinal(inputByte);
        return new String(resultByte, charset);
    }

    private static Cipher getCipher(int mode, String key, String charset,String iv) throws Exception {
        Cipher cipher = CIPHERMAP_MAP.get(mode + "_" + key);
        if (cipher != null) {
            return cipher;
        }

        // secretKeySpec
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(charset), ALGORITHM_NAME);
        // ivParameterSpec
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(charset));
        // cipher
        cipher = Cipher.getInstance(ALGORITHM_STR);
        cipher.init(mode, secretKeySpec, ivParameterSpec);
        // return
        CIPHERMAP_MAP.put(mode + "_" + key, cipher);
        return cipher;
    }

    private static String base64BytesToString(byte[] bytes, String charset) throws Exception {
        return new String(Base64.encodeBase64(bytes), charset);
    }

    private static byte[] base64stringToBytes(String string, String charset) throws Exception {
        return Base64.decodeBase64(string.getBytes(charset));
    }
}

